﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Veralkohol
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:Veralkohol.MyControls;assembly=Veralkohol.MyControls"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:NumericUpDown/>
    ///
    /// </summary>

    public class ValueChangedEventArgs : EventArgs 
    { 
        public int OldValue { get; set; } 
        public int NewValue { get; set; } 
    }

    [TemplatePart(Name = "btnUp", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "btnDown", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "txtValue", Type = typeof(TextBox))]
    public class NumericUpDown : Control
    {
        public event EventHandler<ValueChangedEventArgs> ValueChanged;

        #region Value - Dependency property

        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), new PropertyMetadata(0, new PropertyChangedCallback(ValueChangedCallback)));

        private static void ValueChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) 
        {
            NumericUpDown control = sender as NumericUpDown; 
            if (control == null) return;
            if ((int)args.NewValue > control.MinValue && (int)args.NewValue < control.MaxValue)
            {
                if (control.ValueChanged != null)
                {
                    control.ValueChanged(control, new ValueChangedEventArgs
                    {
                        OldValue = (int)args.OldValue,
                        NewValue = (int)args.NewValue
                    }
                    );
                }
            }
            else if ((int)args.NewValue <= control.MinValue)
            {
                control.Value = control.MinValue;
            }
            else
            {
                control.Value = control.MaxValue;
            }
        }

        #endregion

        #region MinValue - Dependency property
        
        public int MinValue
        {
            get { return (int)GetValue(MinValueProperty); }
            set { SetValue(MinValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MinValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MinValueProperty =
            DependencyProperty.Register("MinValue", typeof(int), typeof(NumericUpDown), new PropertyMetadata(int.MinValue, new PropertyChangedCallback(MinValueChangedCallback)));

        private static void MinValueChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) 
        {
            NumericUpDown control = sender as NumericUpDown; 
            if (control == null) return; 
            if ((int)args.NewValue > control.Value)
            {
                control.Value = (int)args.NewValue;
            }
        }

        #endregion

        #region MaxValue - Dependency property

        public int MaxValue
        {
            get { return (int)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MinValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(int), typeof(NumericUpDown), new PropertyMetadata(int.MaxValue, new PropertyChangedCallback(MaxValueChangedCallback)));

        private static void MaxValueChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            NumericUpDown control = sender as NumericUpDown;
            if (control == null) return;
            if ((int)args.NewValue < control.Value)
            {
                control.Value = (int)args.NewValue;
            }
        }

        #endregion

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            ButtonBase btnUp = this.GetTemplateChild("btnUp") as ButtonBase; 
            if (btnUp != null) btnUp.Click += (sender, args) => Value++;

            ButtonBase btnDown = this.GetTemplateChild("btnDown") as ButtonBase; 
            if (btnDown != null) btnDown.Click += (sender, args) => Value--;

            TextBox txtValue = this.GetTemplateChild("txtValue") as TextBox; 
            if (txtValue != null) 
            { 
                Binding binding = new Binding("Value"); 
                binding.Mode = BindingMode.TwoWay; 
                binding.RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent); 
                txtValue.SetBinding(TextBox.TextProperty, binding); 
            } 
        }

         
        static NumericUpDown()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(NumericUpDown), new FrameworkPropertyMetadata(typeof(NumericUpDown)));
        }
    }
}
